///PHILOTES Source Code.  (C)2012 PhiloLabs
#pragma once


#ifndef __MovableObject_H__
#define __MovableObject_H__

// Precompiler options
#include "OgrePrerequisites.h"
#include "OgreRenderQueue.h"
#include "math/axisAlignedBox.h"
#include "math/sphere.h"
#include "OgreShadowCaster.h"
#include "OgreFactoryObj.h"
#include "OgreAnimable.h"
#include "OgreAny.h"
#include "OgreUserObjectBindings.h"

namespace Ogre {

	// Forward declaration
	class MovableObjectFactory;

	
	
	
    class _OgreExport MovableObject : public ShadowCaster, public AnimableObject, public MemAlloc_SceneObj
    {
    public:
        
        class _OgreExport Listener
        {
        public:
            Listener(void) {}
            virtual ~Listener() {}
            
            virtual void objectDestroyed(MovableObject*) {}
            
            virtual void objectAttached(MovableObject*) {}
            
            virtual void objectDetached(MovableObject*) {}
            
            virtual void objectMoved(MovableObject*) {}
            
            virtual bool objectRendering(const MovableObject*, const Camera*) { return true; }
            
            virtual const LightList* objectQueryLights(const MovableObject*) { return 0; }
        };

    protected:
		/// Name of this object
		String mName;
		/// Creator of this object (if created by a factory)
		MovableObjectFactory* mCreator;
		/// SceneManager holding this object (if applicable)
		SceneManager* mManager;
        /// node to which this object is attached
        Node* mParentNode;
        bool mParentIsTagPoint;
        /// Is this object visible?
        bool mVisible;
		/// Is debug display enabled?
		bool mDebugDisplay;
		/// Upper distance to still render
		Real mUpperDistance;
		Real mSquaredUpperDistance;
		// Minimum pixel size to still render
		Real mMinPixelSize;
		/// Hidden because of distance?
		bool mBeyondFarDistance;	
		/// User objects binding.
		UserObjectBindings mUserObjectBindings;
        /// The render queue to use when rendering this object
        uint8 mRenderQueueID;
		/// Flags whether the RenderQueue's default should be used.
		bool mRenderQueueIDSet;
		/// The render queue group to use when rendering this object
		ushort mRenderQueuePriority;
		/// Flags whether the RenderQueue's default should be used.
		bool mRenderQueuePrioritySet;
        /// Flags determining whether this object is included / excluded from scene queries
        uint32 mQueryFlags;
        /// Flags determining whether this object is visible (compared to SceneManager mask)
        uint32 mVisibilityFlags;
        /// Cached world AABB of this object
        mutable AxisAlignedBox mWorldAABB;
		// Cached world bounding sphere
		mutable Sphere mWorldBoundingSphere;
        /// World space AABB of this object's dark cap
        mutable AxisAlignedBox mWorldDarkCapBounds;
        /// Does this object cast shadows?
        bool mCastShadows;

        /// Does rendering this object disabled by listener?
        bool mRenderingDisabled;
        /// MovableObject listener - only one allowed (no list) for size & performance reasons. */
        Listener* mListener;

        /// List of lights for this object
        mutable LightList mLightList;
        /// The last frame that this light list was updated in
        mutable ulong mLightListUpdated;

		/// the light mask defined for this movable. This will be taken into consideration when deciding which light should affect this movable
		uint32 mLightMask;

		// Static members
		/// Default query flags
		static uint32 msDefaultQueryFlags;
		/// Default visibility flags
		static uint32 msDefaultVisibilityFlags;



    public:
        /// Constructor
        MovableObject();

		/// Named constructor
		MovableObject(const String& name);
        
        virtual ~MovableObject();

		
		virtual void _notifyCreator(MovableObjectFactory* fact) { mCreator = fact; }
		
		virtual MovableObjectFactory*  _getCreator(void) const { return mCreator; }
		
		virtual void _notifyManager(SceneManager* man) { mManager = man; }
		
		virtual SceneManager* _getManager(void) const { return mManager; }

        
		virtual const String& getName(void) const { return mName; }

        
        virtual const String& getMovableType(void) const = 0;

        
        virtual Node* getParentNode(void) const;

        
        virtual SceneNode* getParentSceneNode(void) const;

		/// Gets whether the parent node is a TagPoint (or a SceneNode)
		virtual bool isParentTagPoint() const { return mParentIsTagPoint; }

        
        virtual void _notifyAttached(Node* parent, bool isTagPoint = false);

        
        virtual bool isAttached(void) const;

		
		virtual void detachFromParent(void);

        
        virtual bool isInScene(void) const;

        
        virtual void _notifyMoved(void);

		
        virtual void _notifyCurrentCamera(Camera* cam);

        
        virtual const AxisAlignedBox& getBoundingBox(void) const = 0;

		
		virtual Real getBoundingRadius(void) const = 0;

        
        virtual const AxisAlignedBox& getWorldBoundingBox(bool derive = false) const;
		
        virtual const Sphere& getWorldBoundingSphere(bool derive = false) const;
        
        virtual void _updateRenderQueue(RenderQueue* queue) = 0;

        
        virtual void setVisible(bool visible);

        
        virtual bool getVisible(void) const;

        
        virtual bool isVisible(void) const;

		
		virtual void setRenderingDistance(Real dist) { 
			mUpperDistance = dist; 
			mSquaredUpperDistance = mUpperDistance * mUpperDistance;
		}

		
		virtual Real getRenderingDistance(void) const { return mUpperDistance; }		

		
		virtual void setRenderingMinPixelSize(Real pixelSize) { 
			mMinPixelSize = pixelSize; 
		}

		
		virtual Real getRenderingMinPixelSize() const { 
			return mMinPixelSize; 
		}

		
		virtual void setUserAny(const Any& anything) { getUserObjectBindings().setUserAny(anything); }

		
		virtual const Any& getUserAny(void) const { return getUserObjectBindings().getUserAny(); }

		
		UserObjectBindings&	getUserObjectBindings() { return mUserObjectBindings; }

		
		const UserObjectBindings& getUserObjectBindings() const { return mUserObjectBindings; }

        
        virtual void setRenderQueueGroup(uint8 queueID);

		
		virtual void setRenderQueueGroupAndPriority(uint8 queueID, ushort priority);

        
        virtual uint8 getRenderQueueGroup(void) const;

		/// return the full transformation of the parent sceneNode or the attachingPoint node
		virtual const Matrix4& _getParentNodeFullTransform(void) const;

        
        virtual void setQueryFlags(uint32 flags) { mQueryFlags = flags; }

        
        virtual void addQueryFlags(uint32 flags) { mQueryFlags |= flags; }
            
        
        virtual void removeQueryFlags(uint32 flags) { mQueryFlags &= ~flags; }
        
        /// Returns the query flags relevant for this object
        virtual uint32 getQueryFlags(void) const { return mQueryFlags; }

		
		static void setDefaultQueryFlags(uint32 flags) { msDefaultQueryFlags = flags; }

		
		static uint32 getDefaultQueryFlags() { return msDefaultQueryFlags; }

		
        
        virtual void setVisibilityFlags(uint32 flags) { mVisibilityFlags = flags; }

        
        virtual void addVisibilityFlags(uint32 flags) { mVisibilityFlags |= flags; }
            
        
        virtual void removeVisibilityFlags(uint32 flags) { mVisibilityFlags &= ~flags; }
        
        /// Returns the visibility flags relevant for this object
        virtual uint32 getVisibilityFlags(void) const { return mVisibilityFlags; }

		
		static void setDefaultVisibilityFlags(uint32 flags) { msDefaultVisibilityFlags = flags; }
		
		
		static uint32 getDefaultVisibilityFlags() { return msDefaultVisibilityFlags; }

        
        virtual void setListener(Listener* listener) { mListener = listener; }

        
        virtual Listener* getListener(void) const { return mListener; }

        
        virtual const LightList& queryLights(void) const;

		
		virtual uint32 getLightMask()const { return mLightMask; }
		
		virtual void setLightMask(uint32 lightMask);

		
		virtual LightList* _getLightList() { return &mLightList; }

		/// Define a default implementation of method from ShadowCaster which implements no shadows
        EdgeData* getEdgeList(void) { return NULL; }
		/// Define a default implementation of method from ShadowCaster which implements no shadows
		bool hasEdgeList(void) { return false; }
        /// Define a default implementation of method from ShadowCaster which implements no shadows
        ShadowRenderableListIterator getShadowVolumeRenderableIterator(
            ShadowTechnique shadowTechnique, const Light* light, 
            HardwareIndexBufferSharedPtr* indexBuffer, 
            bool extrudeVertices, Real extrusionDist, unsigned long flags = 0);
		
        
        const AxisAlignedBox& getLightCapBounds(void) const;
        
        const AxisAlignedBox& getDarkCapBounds(const Light& light, Real dirLightExtrusionDist) const;
        
        void setCastShadows(bool enabled) { mCastShadows = enabled; }
        
        bool getCastShadows(void) const { return mCastShadows; }
		
		bool getReceivesShadows();
			
        
        Real getPointExtrusionDistance(const Light* l) const;
		
		virtual uint32 getTypeFlags(void) const;

		
		virtual void visitRenderables(Renderable::Visitor* visitor, 
			bool debugRenderables = false) = 0;

		
		virtual void setDebugDisplayEnabled(bool enabled) { mDebugDisplay = enabled; }
		/// Gets whether debug display of this object is enabled. 
		virtual bool isDebugDisplayEnabled(void) const { return mDebugDisplay; }





    };

	
	class _OgreExport MovableObjectFactory : public MemAlloc_SceneObj
	{
	protected:
		/// Type flag, allocated if requested
		unsigned long mTypeFlag;

		/// Internal implementation of create method - must be overridden
		virtual MovableObject* createInstanceImpl(
			const String& name, const NameValuePairList* params = 0) = 0;
	public:
		MovableObjectFactory() : mTypeFlag(0xFFFFFFFF) {}
		virtual ~MovableObjectFactory() {}
		/// Get the type of the object to be created
		virtual const String& getType(void) const = 0;

		
		virtual MovableObject* createInstance(
			const String& name, SceneManager* manager, 
			const NameValuePairList* params = 0);
		
		virtual void destroyInstance(MovableObject* obj) = 0;

		
		virtual bool requestTypeFlags(void) const { return false; }
		
		void _notifyTypeFlags(unsigned long flag) { mTypeFlag = flag; }

		
		uint32 getTypeFlags(void) const { return mTypeFlag; }

	};
	
	

}
#endif
